#ifndef __GE__HPP__
#define __GE__HPP__
// CmpGE
struct CmpGE {
  static std::string name() { return "CMPGE"; }
  constexpr static bool apply (int l, int h) { 
    return (l >= h);
  }
};

template< class A, class B>
constexpr Expression<BinaryExpression<Expression<A>, Expression<B>, CmpGE> >
operator>=(Expression<A> const & a, Expression<B> const & b)
{
  typedef BinaryExpression <Expression<A>, Expression<B>, CmpGE> ExprT;
  return Expression<ExprT>(ExprT(a,b));
}

// Can we do without this ? Specializations don't overload !
template <int PLACE, class A, bool B>
constexpr Expression<BinaryExpression<Expression<A>, Term<PLACE, Var, B>, CmpGE> >
operator>=(Expression<A> const & a, Term<PLACE, Var, B> const & b)
{
  typedef BinaryExpression <Expression<A>, Term<PLACE, Var, B>, CmpGE> ExprT;
  return Expression<ExprT>(ExprT(a,b));
}

// Can we do without this ? Specializations don't overload !
template <int PLACE, bool A, class B>
constexpr Expression<BinaryExpression<Term<PLACE, Var, A>, Expression<B>, CmpGE> >
operator>=(Term<PLACE, Var, A> const & a, Expression<B> const & b)
{
  typedef BinaryExpression <Term<PLACE, Var, A>, Expression<B>, CmpGE> ExprT;
  return Expression<ExprT>(ExprT(a,b));
}

// Can we do without this ? Specializations don't overload !
template <int PLACEA, int PLACE, bool A, bool B>
constexpr Expression<BinaryExpression<Term<PLACEA, Var, A>, Term<PLACE, Var, B>, CmpGE> >
operator>=(Term<PLACEA, Var, A> const & a, Term<PLACE, Var, B> const & b)
{
  typedef BinaryExpression <Term<PLACEA, Var, A>, Term<PLACE, Var, B>, CmpGE> ExprT;
  return Expression<ExprT>(ExprT(a,b));
}

// Can we do without this ? Specializations don't overload !
template <class A>
constexpr Expression<BinaryExpression<Expression<A>, ConstantTerm, CmpGE> >
operator>=(Expression<A> const & a, int const & b)
{
  typedef BinaryExpression <Expression<A>, ConstantTerm, CmpGE> ExprT;
  return Expression<ExprT>(ExprT(a,ConstantTerm(b)));
}

// Can we do without this ? Specializations don't overload !
template <class B>
constexpr Expression<BinaryExpression<ConstantTerm, Expression<B>, CmpGE> >
operator>=(int const & a, Expression<B> const & b)
{
  typedef BinaryExpression <ConstantTerm, Expression<B>, CmpGE> ExprT;
  return Expression<ExprT>(ExprT(ConstantTerm(a),b));
}

template <int PLACEA, int PLACE>
constexpr Expression<BinaryExpression<Expression<VariableTerm<PLACEA> >, Expression<VariableTerm<PLACE> >, CmpGE> >
operator>=(VariableTerm<PLACEA> const & a, VariableTerm<PLACE> const & b) {
  typedef BinaryExpression <Expression<VariableTerm<PLACEA> >, Expression<VariableTerm<PLACE> >, CmpGE> ExprT;
  return Expression<ExprT>(ExprT(Expression<VariableTerm<PLACEA> >(a),Expression<VariableTerm<PLACE> >(b)));
}
template <int PLACE>
constexpr Expression<BinaryExpression<Expression<ConstantTerm>, Expression<VariableTerm<PLACE> >, CmpGE> >
operator>=(ConstantTerm const & a, VariableTerm<PLACE> const & b) {
  typedef BinaryExpression <Expression<ConstantTerm>, Expression<VariableTerm<PLACE> >, CmpGE> ExprT;
  return Expression<ExprT>(ExprT(Expression<ConstantTerm>(a),Expression<VariableTerm<PLACE> >(b)));
}
template <int PLACE>
constexpr Expression<BinaryExpression<Expression<VariableTerm<PLACE> >, Expression<ConstantTerm>, CmpGE> >
operator>=(VariableTerm<PLACE> const & b, ConstantTerm const & a) {
  typedef BinaryExpression <Expression<VariableTerm<PLACE> >, Expression<ConstantTerm>, CmpGE> ExprT;
  return Expression<ExprT>(ExprT(Expression<VariableTerm<PLACE> >(b), Expression<ConstantTerm>(a)));
}
constexpr Expression<BinaryExpression<Expression<ConstantTerm>, Expression<ConstantTerm>, CmpGE> >
operator>=(ConstantTerm const & b, ConstantTerm const & a) {
  typedef BinaryExpression <Expression<ConstantTerm>, Expression<ConstantTerm>, CmpGE> ExprT;
  return Expression<ExprT>(ExprT(Expression<ConstantTerm>(b), Expression<ConstantTerm>(a)));
}

#endif //__GE__HPP__
